package cn.gemframe.security.handler;

import cn.gemframe.common.bean.response.AccessTokenResp;
import cn.gemframe.constant.GemConstant;
import cn.gemframe.exception.GemException;
import cn.gemframe.exception.status.GemErrorStatus;
import cn.gemframe.config.security.bean.GemUserDetails;
import cn.gemframe.response.ResultData;
import cn.gemframe.utils.GemIPUtlis;
import cn.gemframe.utils.GemJsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

/**
 * 登录成功handler
 */
@Component
public class GemLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

	@Autowired
	private ValueOperations<String, Object> valueOperations;
	@Autowired
	private ClientDetailsService clientDetailsService;
	@Autowired
	private AuthorizationServerTokenServices authorizationServerTokenServices;

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setContentType(GemConstant.MediaType.JSON_UTF_8);

		String headerUsername = GemConstant.Auth.CLIENT_ID_NAME;
		String headerPassword = GemConstant.Auth.CLIENT_ID_PASS;
		byte[] encode = Base64.encode(String.valueOf(headerUsername+":"+headerPassword).getBytes());
		String header = "Basic " + new String(encode);
		String[] tokens = extractAndDecodeHeader(header, request);
		assert tokens.length == GemConstant.Number.TWO;
		String clientId = tokens[GemConstant.Number.ZERO];
		String clientSecret = tokens[GemConstant.Number.ONE];
		
		ClientDetails loadClientByClientId = clientDetailsService.loadClientByClientId(clientId);
		if(loadClientByClientId==null){
			response.getWriter().write(GemJsonUtils.objectToJson(authentication));
			return;
		}
		if(!StringUtils.equals(clientSecret, loadClientByClientId.getClientSecret())){
			response.getWriter().write(GemJsonUtils.objectToJson(authentication));
			return;
		}
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		TokenRequest tokenRequest = new TokenRequest(new HashMap(1), clientId, loadClientByClientId.getScope(), "custom");
		OAuth2Request createOAuth2Request = tokenRequest.createOAuth2Request(loadClientByClientId);
		OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(createOAuth2Request, authentication);
		OAuth2AccessToken createAccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
		GemUserDetails userData = GemUserDetails.getUserData();
		AccessTokenResp accessTokenResp  = AccessTokenResp.builder()
				.access_token(createAccessToken.getValue())
				.token_type(createAccessToken.getTokenType())
				.refresh_token(createAccessToken.getRefreshToken().getValue())
				.expires_in(createAccessToken.getExpiresIn()).build();
		String userId = userData.getUserId();
		if(userId!=null && !userId.equalsIgnoreCase("null") && userId.length()>0) {
			accessTokenResp.setUserid(userId);
		}
		String username = userData.getUsername();
		if(username!=null && !username.equalsIgnoreCase("null") && username.length()>0) {
			accessTokenResp.setUsername(username);
		}
		if(valueOperations!=null) {
			//设置缓存
			valueOperations.set(GemIPUtlis.getIpAddr(request), userId+"<@>"+username);
		}

		//TODO: 登录成功后查询用户权限，初始化用户权限，或者在用户请求权限接口时赋予
		response.setStatus(HttpStatus.OK.value());
		response.getWriter().write(GemJsonUtils.objectToJson(ResultData.SUCCESS(accessTokenResp)));
	}


	/**
	 * 创建token
	 * @param header
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private String[] extractAndDecodeHeader(String header, HttpServletRequest request)
			throws IOException {

		byte[] base64Token = header.substring(GemConstant.Number.SIX).getBytes(GemConstant.Character.UTF8);
		byte[] decoded;
		try {
			decoded = Base64.decode(base64Token);
		}catch (IllegalArgumentException e) {
			throw new GemException(GemErrorStatus.CREATE_TOKEN_ERROR);
		}

		String token = new String(decoded, GemConstant.Character.UTF8);
		int delim = token.indexOf(":");
		if (delim == -1) {
			throw new GemException(GemErrorStatus.CREATE_TOKEN_ERROR);
		}
		return new String[] { token.substring(GemConstant.Number.ZERO, delim), token.substring(delim + GemConstant.Number.ONE) };
	}
}
